package com.liu.concurrent;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author liubo
 */
public class MultiplexerTimeServer implements Runnable {
	private Selector selector;

	private ServerSocketChannel serverChannel;

	private volatile boolean stop;

	public void stop() {
		this.stop = true;
	}

	public MultiplexerTimeServer(int port) {
		try {
			// 负责轮询是否有新的连接
			selector = Selector.open();

			// 启动服务端ServerSocketChannel，监听客户端连接
			serverChannel = ServerSocketChannel.open();
			// 设置为非阻塞（阻塞/非阻塞）连接模式
			serverChannel.configureBlocking(false);
			// 绑定端口，设置待办事件为1024
			serverChannel.socket().bind(new InetSocketAddress(port), 1024);
			// 将Channel注册到Selector上，监听ACCEPT事件
			serverChannel.register(selector, SelectionKey.OP_ACCEPT);
		} catch (IOException e) {
			e.printStackTrace();
			// 如果资源初始化失败（如端口被占），则退出程序。
			System.exit(1);
		}
	}

	@Override
	public void run() {
		while (!stop) {
			try {
				/**
				 * 每隔timeout毫秒唤醒一次,当有处于就绪状态的Channel时,selector将返回就绪状态Channel的selectionKeys集合,
				 * 通过对就绪状态Channel集合进行迭代，可以进行网络的异步读写操作
				 */
				selector.select(1);
				Set<SelectionKey> selectionKeys = selector.selectedKeys();
				Iterator<SelectionKey> it = selectionKeys.iterator();
				SelectionKey key = null;
				while (it.hasNext()) {
					key = it.next();
					it.remove();
					handleInput(key);
					if (key != null) {
						key.cancel();
						if (key.channel() != null) {
							key.channel().close();
						}
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		new Thread().start();

		//step1 创建Lock对象
		ReentrantLock lock = new ReentrantLock();

		//step2 加锁
		lock.lock();

		try {
			//业务代码
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			//step3 解锁
			lock.unlock();
		}

		// 多路复用器关闭后，所有注册在上面的Channel和Pipe等资源都会被自动去注册并关闭，所以不需要重复释放资源
		if (selector != null) {
			try {
				selector.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void handleInput(SelectionKey key) throws IOException {
		if (key.isValid()) {
			// 处理新接入的请求消息,通过SelectionKey的值获知网络事件的类型
			if (key.isAcceptable()) {
				//接收到客户端的连接请求
				ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
				SocketChannel sc = ssc.accept();
				sc.configureBlocking(false);
				sc.register(selector, SelectionKey.OP_READ);
			}
			if (key.isReadable()) {
				//读取客户端的请求消息
				SocketChannel sc = (SocketChannel) key.channel();
				//设置缓冲区大小
				ByteBuffer readBuffer = ByteBuffer.allocate(1024);
				int readBytes = sc.read(readBuffer);
				if (readBytes > 0) {
					// 对读取到字节进行编解码
					//将当前缓冲区的limit设置为position,position为0,用于后续对缓冲区的读取操作
					readBuffer.flip();
					//根据缓冲区字节个数创建字节数组
					byte[] bytes = new byte[readBuffer.remaining()];
					//将缓冲区可读的字节数组复制到新创建的字节数组中
					readBuffer.get(bytes);
					String body = new String(bytes, "UTF-8");

				} else if (readBytes < 0) {
					// 对方已经关闭链路连接,释放资源
					key.cancel();
					sc.close();
				} else {// 没有读取到字节

				}
			}
		}
	}
}
